""""""
"""
______________________________
time：2021/6/23
______________________________

对selenium操作的二次封装： basepage
1.实现失败操作自动截图和保存日志；
2.简化当前对代码的调用；

以下这六个方法是必须封装的； app自动化一模一样；
1.等待元素可见
2.查找元素
3.点击操作：等待——查找——点击
4.输入操作：等待——查找——输入
5.获取元素文本：等待——查找定位元素——获取文本
6.获取元素属性：等待——查找定位元素——获取属性
7.窗口切换

关键字驱动思想：之后的robot也是对selenium进行二次封装，然后我们只需调用这些关键字即可；

"""
import os
import time

from selenium import webdriver
from selenium.webdriver.remote.webdriver import WebDriver
from selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By

from Common.my_logger import logger
from Common.handle_path import screenshot_dir


class Basepage:
    def __init__(self, driver: WebDriver):
        self.driver = driver
        self.wait = WebDriverWait(driver, 20)

    # 等待页面元素可见
    def wait_element_visible(self, locator, page_action, timeout=20,
                             poll_frequency=0.5):  # locator，包含元素定位策略和表达式，调用时才知道定位的什么
        """

        param locator: 数组，传入元素定位的信息；
        param page_action:str，对当前页面的操作行为，为了截图命名规范用及日志打印，类似于注释；
        param timeout:
        param poll_frequency:
        return:
        """
        logger.info("在 {} 的行为中，等待元素：{}可见。".format(page_action, locator))
        try:
            starttime = time.time()
            WebDriverWait(self.driver, timeout, poll_frequency).until(EC.visibility_of_element_located(locator))
        except:
            """如果等待异常，则1：输出到日志文件；2.失败则截图当前页面；"""
            logger.exception("等待元素可见——失败。")
            self.get_screenshot(page_action)
            raise
        else:
            endtime = time.time()
            logger.info("等待元素可见成功，等待耗时为：{}".format(endtime - starttime))

    # 等待页面元素存在
    def wait_page_contains_element(self, locator, page_action, timeout=20,
                                   poll_frequency=0.5):
        logger.info("在 {} 的行为中，等待元素：{} 存在。".format(page_action, locator))
        try:
            starttime = time.time()
            WebDriverWait(self.driver, timeout, poll_frequency).until(EC.presence_of_element_located(locator))
        except:
            logger.exception("等待元素存在——失败。")
            self.get_screenshot(page_action)
            raise
        else:
            endtime = time.time()
            logger.info("等待元素存在成功，等待耗时为：{}".format(endtime - starttime))

    # 查找元素
    def get_element(self, locator, page_action, timeout=20,
                    poll_frequency=0.5, wait=None):
        if wait:
            self.wait_page_contains_element(locator, page_action, timeout, poll_frequency)
        else:
            self.wait_element_visible(locator, page_action, timeout, poll_frequency)

        logger.info("在 {} 的行为中，查找元素：{}。".format(page_action, locator))
        try:
            element = self.driver.find_element(*locator)
        except:
            logger.exception("查找元素操作——失败。")
            self.get_screenshot(page_action)
            raise
        else:
            return element

    # 点击操作
    def click_element(self, locator, page_action, timeout=20,
                      poll_frequency=0.5):
        # 等待——查找——点击
        element = self.get_element(locator, page_action, timeout, poll_frequency)
        logger.info("在 {} 的行为中，点击元素：{}。".format(page_action, locator))
        try:
            element.click()
        except:
            logger.exception("点击元素操作——失败。")
            self.get_screenshot(page_action)
            raise

    # 输入操作
    def input_element(self, locator, page_action, value, timeout=20,
                      poll_frequency=0.5):
        # 等待——查找——输入
        element = self.get_element(locator, page_action, timeout, poll_frequency)
        logger.info("在 {} 的行为中，给元素：{} 输入文本值：{}。".format(page_action, locator, value))
        try:
            element.clear()
            element.send_keys(value)
        except:
            logger.exception("元素输入操作——失败。")
            self.get_screenshot(page_action)
            raise

    # 获取元素文本
    def get_text(self, locator, page_action, timeout=20,
                 poll_frequency=0.5):
        # 等待元素存在——查找定位元素——获取文本
        # 建议封装为：等待元素存在，app自动化中有个应用场景：等待元素存在并获取元素文本；
        element = self.get_element(locator, page_action, timeout, poll_frequency, wait=True)
        logger.info("在 {} 的行为中，获取元素：{} 的文本值.".format(page_action, locator))
        try:
            ele_text = element.text
        except:
            logger.exception("获取元素文本操作——失败。")
            self.get_screenshot(page_action)
            raise
        else:
            logger.info("文本值为：{}".format(ele_text))
            return ele_text

    # 获取元素属性
    def get_element_attribute(self, locator, page_action, attr, timeout=20,
                              poll_frequency=0.5):
        # 等待——查找定位元素——获取属性
        element = self.get_element(locator, page_action, timeout, poll_frequency, wait=True)
        logger.info("在 {} 的行为中，获取元素：{} 的{}属性值。".format(page_action, locator, attr))
        try:
            attr_value = element.get_attribute(attr)
        except:
            logger.exception("获取元素属性操作——失败。")
            self.get_screenshot(page_action)
            raise
        else:
            logger.info("元素的属性值为：{}".format(attr))
            return attr_value

    def get_screenshot(self, page_action):
        # 命名规范：XX页面_XX操作_截图时间.png
        nowtime = time.strftime('%Y-%m-%d-%H-%M-%S', time.localtime())
        file_path = os.path.join(screenshot_dir, "{}_{}.png".format(page_action, nowtime))
        self.driver.save_screenshot(file_path)
        logger.info("截图保存在目录：{}".format(file_path))

    """
    窗口切换的流程：
    1. 导致新窗口出现的动作；
    2.获取所有已打开的窗口句柄window_handles；
    3.获取当前打开的窗口句柄current_window_handle；
    4. 切换窗口：driver.switch_to.window(窗口句柄)
    """

    # 切换窗口
    def switch_window(self, name="new"):
        time.sleep(1)
        win_hans = self.driver.window_handles
        if name == "new":
            driver.switch_to.window(win_hans[-1])

    # 回退到上一页
    def back_last_page(self, page_action):
        logger.info("回退到上一页面。")
        try:
            self.driver.back()
        except:
            logger.exception("回退到上一页面——失败。")
            self.get_screenshot(page_action)
            raise

    # 刷新当前页面
    def refresh_page(self, page_action):
        logger.info("刷新当前页面。")
        try:
            self.driver.refresh()
        except:
            logger.exception("刷新当前页面——失败。")
            self.get_screenshot(page_action)
            raise


if __name__ == '__main__':
    driver = webdriver.Chrome()
    base = Basepage(driver)
    driver.get("https://www.baidu.com")
    loc = ("id", "kw")
    loc_button = ("id", "su")
    base.input_element(loc, "百度首页_输入搜索内容", "我思故我在")
    base.click_element(loc_button, "百度首页_点击搜索按钮")
    time.sleep(3)

    loc_text = (By.XPATH, '//div[@id="u"]//a[@class="toindex"]')
    print("获取元素文本的值：", base.get_text(loc_text, "百度_获取元素文本值"))
    loc_attr = (By.XPATH, '//input[@value="百度一下"]')
    print("获取元素的属性：", base.get_element_attribute(loc_attr, "百度_获取元素的属性", "type"))

    time.sleep(5)
    driver.quit()
